package cn.demoxy.handler;

import cn.demoxy.annotation.Log;
import cn.demoxy.enums.BusinessTypeEnum;
import cn.demoxy.mapper.DemoLogMapper;
import cn.demoxy.model.entity.DemoLog;
import cn.demoxy.model.entity.DemoUser;
import cn.demoxy.result.ResultCodeEnum;
import cn.demoxy.service.IDemoLogService;
import cn.demoxy.service.IDemoUserService;
import cn.demoxy.utils.IpUtils;
import cn.demoxy.utils.JWTUtils;
import cn.demoxy.utils.ServletUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * @auther demo
 * @date 2022/5/19 21:20
 * 系统日志：切面处理类
 */
@Aspect
@Component
@AllArgsConstructor
public class LogAspectHandler {

    /**
     * 接口之前之前的时间戳(ms)
     */
    private static Long beforeTime = null;

    /**
     * 日志service
     */
    private IDemoLogService logService;


    private IDemoUserService userService;

    /**
     * 定义切点根据带了@Log注解的接口开始切入方法
     * @param controllerLog
     */
    @Pointcut(value = "@annotation(controllerLog)")
    private void pt1(Log controllerLog) {
    }

    /**
     * 获取接口执行前的时间
     * @param controllerLog
     */
    @Before("pt1(controllerLog)")
    public void before(Log controllerLog) {
        Long time = System.currentTimeMillis();
        beforeTime = time;

    }

    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) throws Exception {
        handleLog(joinPoint, controllerLog, null, jsonResult);
    }

    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
        DemoLog log = new DemoLog();
        long end = System.currentTimeMillis();
        //计算接口响应时间(ms)
        long responseTime = end - beforeTime;
        log.setTime(String.valueOf(responseTime));
        // *========数据库日志=========*//
        //获取调用ip地址
        String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
        JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(jsonResult));
        String code = jsonObject.getString("code");
        log.setStatus(code);
            //是登录接口
            if (SecurityUtils.getSubject().getPrincipal() == null) {
                if (controllerLog.businessType().equals(BusinessTypeEnum.LOGIN)) {
                    //判断是否登录成功,如果成功将用户名存入日志
                    if (String.valueOf(ResultCodeEnum.SUCCESS.getCode()).equals(code)) {
                        Object userParams = joinPoint.getArgs()[0];
                        String username = JSONObject.parseObject(JSON.toJSONString(userParams)).getString("username");
                        log.setUser(username);
                    }
                } else if (controllerLog.businessType().equals(BusinessTypeEnum.LOGOUT)) {
                    String username = jsonObject.getString("data");
                    log.setUser(username);
                }

            }else {
                // 获取当前的用户
                String token = SecurityUtils.getSubject().getPrincipal().toString();
                String name = JWTUtils.getUsername(token);
                DemoUser user = userService.findByUserName(name);
                log.setUser(user.getUsername());
            }
        log.setRemoteAddr(ip);
        log.setRequestUri(String.valueOf(ServletUtils.getRequest().getRequestURI()));
        log.setMethod(ServletUtils.getRequest().getMethod());
        getControllerMethodDescription(joinPoint, controllerLog, log, jsonResult);
        logService.save(log);
    }

    /**
     *获取注解中对方法的描述信息 用于Controller层注解
     * @param joinPoint
     * @param controllerLog
     * @param log
     * @param jsonResult
     */
    private void getControllerMethodDescription(JoinPoint joinPoint, Log controllerLog, DemoLog log, Object jsonResult) {
        // 设置action动作
        log.setBusinessType(controllerLog.businessType().getDes());
        // 设置模块名称
        log.setTitle(controllerLog.title());
    }
}
